OS: Windows 10
Editor: Visual Studio Code
Rust version: 1.63.0
今天簡單了解一下Rust中的泛型,真的是簡單而已,因為後面還有一個看整天感覺熟悉,但又很陌生的功能-特徵(trait),但以下的內容還是會牽扯到特徵的功能。
如同其他語言,在邏輯上可能做一樣的事,例如比大小找出最大值,但因為型別不同需要,寫出出各自的版本,這時就會使用泛型。
以找出序列中的最大值為例,這是範例資料:
let list = vec![2.0, 2.5, 1.0, 0.9, 3.2];
let max_in_list = max(&list);
println!("Max in list: {}", max_in_list);
這是功能實作
fn max<T>(list: &[T]) -> T {
    let mut max = list[0];
    for &item in list {
        if item > max {
            max = item;
        }
    }
    max
}
執行的會,compiler會丟出一段錯誤:
Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0369]: binary operation `>` cannot be applied to type `T`
  --> src\main.rs:36:17
   |
36 |         if item > max {
   |            ---- ^ --- T
   |            |
   |            T
   |
help: consider restricting type parameter `T`
   |
33 | fn max<T: std::cmp::PartialOrd>(list: &[T]) -> T {
   |         ++++++++++++++++++++++
For more information about this error, try `rustc --explain E0369`.
內容是說,如果要比大小,泛型的型別是要有實作>符號,也就是錯誤訊息提到的std::cmp::PartialOrd特徵。
所以改成這樣,有點像C#的where來限制可用的型別:
fn max<T: PartialOrd>(list: &[T]) -> T {
    let mut max = list[0];
    for &item in list {
        if item > max {
            max = item;
        }
    }
    max
}
但還是會跟你抱怨錯誤:
Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0508]: cannot move out of type `[T]`, a non-copy slice
  --> src\main.rs:34:19
   |
34 |     let mut max = list[0];
   |                   ^^^^^^^
   |                   |
   |                   cannot move out of here
   |                   move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait
   |                   help: consider borrowing here: `&list[0]`
error[E0507]: cannot move out of a shared reference
  --> src\main.rs:35:18
   |
35 |     for &item in list {
   |         -----    ^^^^
   |         ||
   |         |data moved here
   |         |move occurs because `item` has type `T`, which does not implement the `Copy` trait
   |         help: consider removing the `&`: `item`
Some errors have detailed explanations: E0507, E0508.
For more information about an error, try `rustc --explain E0507`.
compiler告訴我們,型別若沒有實作Copy,則資料的所有權會發生問題,我們就照compiler的建議,再加上限制,有實作Copy的型別才能使用,這時我們使用+來限制:
fn max<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut max = list[0];
    for &item in list {
        if item > max {
            max = item;
        }
    }
    max
}
之前就很常在用了,例如向量(vector)跟雜湊表(hash map)就是泛型的型別,下面示範如何定義泛型型別:
struct Point<T> {
    x: T,
    y: T,
}
如果要定義泛型型別的方法(methods):
impl<T> Point<T> {
    fn move_to(&mut self, nx: T, ny: T) {
        self.x = nx;
        self.y = ny;
    }
}
// example
let mut p = Point { x: 1.0, y: 2.0 };
p.move_to(15.0, 13.0);
然後,假如只指定一些泛型可以用,例如:
impl Point<bool> {
    fn reset(&mut self) {
        self.x = false;
        self.y = false;
    }
}
上面的例子就會是,當Point<T>是用bool型別的時候,才能使用reset。
let mut pbool = Point { x: true, y: false };
pbool.reset();
let mut p = Point { x: 1.0, y: 2.0 };
p.reset();
錯誤訊息:
Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0599]: no method named `reset` found for struct `Point<{float}>` in the current scope
  --> src\main.rs:48:7
   |
3  | struct Point<T> {
   | --------------- method `reset` not found for this
...
48 |     p.reset();
   |       ^^^^^ method not found in `Point<{float}>`
   |
   = note: the method was found for
           - `Point<bool>`
For more information about this error, try `rustc --explain E0599`.
compiler會告訴你只有Point<bool>有reset的實作。